

#include "LecteurPhraseAbstrait.h"
#include "LecteurFonction.h"



#include <stdlib.h>

#include <iostream>

using namespace std;



////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAbstrait::LecteurPhraseAbstrait() : ts() {
}



////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAbstrait::analyse() {
    arbre = programme();
    cout << "Syntaxe correcte." << endl;
}



////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAbstrait::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }
    NoeudSeqInst* si = new NoeudSeqInst();
    do {
        si->ajouteInstruction(inst());
        sauterSymCour(";");
    } while (ls->getSymCour() == "<VARIABLE>" || ls->getSymCour() == "si" ||
            ls->getSymCour() == "tantque" || ls->getSymCour() == "repeter" ||
            ls->getSymCour() == "lire" || ls->getSymCour() == "ecrire" ||
            ls->getSymCour() == "pour");
    // tant que le symbole courant est un debut possible d'instruction...
    return si;
}



////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAbstrait::inst() {

    // <inst> ::= <affectation> | <inst_condi>

    if (ls->getSymCour() == "si")

        return instSi();

    else if (ls->getSymCour() == "tantque")

        return instTq();

    else if (ls->getSymCour() == "repeter")

        return instRepeter();

    else if (ls->getSymCour() == "lire")

        return instLire();

    else if (ls->getSymCour() == "ecrire")

        return instEcrire();

    else if (ls->getSymCour() == "pour")

        return instPour();

    else {

        testerSymCour("<VARIABLE>");

        Symbole s(ls->getSymCour());

        ls->suivant();

        if (ls->getSymCour() == "(")

            return fonction(s);

        else

            return affectation(s);

    }

}



////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAbstrait::fonction(Symbole &s) {
    sauterSymCour("(");
    unsigned i;
    for (i = 0; i<tf.size(); i++) {
        if (((LecteurFonction*) tf[i])->getNom() == s.getChaine())
            break;
    }
    if (i==tf.size()){
        erreur(";");
    }
    NoeudFonction *n = new NoeudFonction(((LecteurFonction*) tf[i]));
    for (unsigned j = 0; j < ((LecteurFonction*) tf[i])->getNbParam(); j++) {
        Noeud *n2 = expression();
        n->ajoute(n2);
        if (j < (((LecteurFonction*) tf[i])->getNbParam()) - 1)
            sauterSymCour(",");
    }
    sauterSymCour(")");
    return n;

}

Noeud* LecteurPhraseAbstrait::affectation() {
    // <affectation> ::= <variable> = <expression>
    testerSymCour("<VARIABLE>");
    Symbole s(ls->getSymCour());
    ls->suivant();
    return affectation(s);
}

Noeud* LecteurPhraseAbstrait::affectation(Symbole &s) {

    Noeud* exp = NULL;

    Noeud* var = ts.chercheAjoute(s);

    if (ls->getSymCour() == "=") {

        ls->suivant();

        exp = expression();

    } else if (ls->getSymCour() == "++") {

        ls->suivant();

        exp = new NoeudOperateurBinaire(Symbole("+"), var, ts.chercheAjoute(Symbole("1")));

    } else if (ls->getSymCour() == "--") {

        ls->suivant();

        exp = new NoeudOperateurBinaire(Symbole("-"), var, ts.chercheAjoute(Symbole("1")));

    }



    return new NoeudAffectation(var, exp);

}



////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAbstrait::expression() {
    // <expression> ::= <facteur> { <opBinaire> <facteur> }
    Noeud* fact = terme();
    while (ls->getSymCour() == "+" || ls->getSymCour() == "-") {
        Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
        Noeud* factDroit = terme(); // lecture de l'operande droit
        fact = new NoeudOperateurBinaire(operateur, fact, factDroit); // const. du noeud
    }
    return fact;
}

Noeud* LecteurPhraseAbstrait::terme() {

    // <expression> ::= <facteur> { <opMult> <facteur> }

    Noeud* fact = facteur();

    while (ls->getSymCour() == "*" || ls->getSymCour() == "/") {

        Symbole operateur = opMult();

        Noeud* fact2 = facteur();

        fact = new NoeudOperateurBinaire(operateur, fact, fact2);

    }

    return fact;

}



////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAbstrait::facteur() {
    // <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
    Noeud* fact = NULL;
    if (ls->getSymCour() == "<VARIABLE>") {
        Symbole s(ls->getSymCour());
        ls->suivant();
        if (ls->getSymCour() == "(")
            fact = fonction(s);
        else{
            fact = ts.chercheAjoute(s);
        }
    } else if (ls->getSymCour() == "<ENTIER>") {
        fact = ts.chercheAjoute(ls->getSymCour());
        ls->suivant();
    } else if (ls->getSymCour() == "-" || ls->getSymCour() == "non") {
        Symbole s = ls->getSymCour();
        ls->suivant();
        // on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
        fact = new NoeudOperateurBinaire(s, ts.chercheAjoute(Symbole("0")), expBool());
    } else if (ls->getSymCour() == "(") {
        ls->suivant();
        fact = expBool();
        sauterSymCour(")");
    } else
        erreur("<facteur>");
    return fact;
}

Symbole LecteurPhraseAbstrait::opAdd() {

    Symbole operateur = ls->getSymCour();

    if (ls->getSymCour() == "+" || ls->getSymCour() == "-") {

        ls->suivant();

    } else

        erreur("<opAdd>");

    return operateur;

}



////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAbstrait::opMult() {

    Symbole operateur = ls->getSymCour();

    if (ls->getSymCour() == "*" || ls->getSymCour() == "/") {

        ls->suivant();

    } else

        erreur("<opMult>");

    return operateur;

}

Symbole LecteurPhraseAbstrait::opBool() {

    Symbole operateur = ls->getSymCour();

    if (ls->getSymCour() == "et" || ls->getSymCour() == "ou") {

        ls->suivant();

    } else {

        erreur("<opBool>");

    }

    return operateur;

}

Noeud* LecteurPhraseAbstrait::expBool() {

    Noeud* expet = expEt();

    while (ls->getSymCour() == "ou") {

        Symbole operateur = opBool();

        Noeud* expet2 = expEt();

        expet = new NoeudOperateurBinaire(operateur, expet, expet2);

    }

    return expet;

}

Noeud* LecteurPhraseAbstrait::expEt() {

    Noeud* rel = relation();

    while (ls->getSymCour() == "et") {

        Symbole operateur = opBool();

        Noeud* rel2 = relation();

        rel = new NoeudOperateurBinaire(operateur, rel, rel2);

    }

    return rel;

}

Symbole LecteurPhraseAbstrait::opRel() {

    Symbole operateur = ls->getSymCour();

    if (ls->getSymCour() == "==" || ls->getSymCour() == "!=" ||

            ls->getSymCour() == ">=" || ls->getSymCour() == "<=" ||

            ls->getSymCour() == ">" || ls->getSymCour() == "<") {

        ls->suivant();

    } else {

        erreur("<opRel>");

    }

    return operateur;

}

Symbole LecteurPhraseAbstrait::opUnaire() {

    Symbole operateur = ls->getSymCour();

    if (ls->getSymCour() == "-" || ls->getSymCour() == "non") {

        ls->suivant();

    } else {

        erreur("<opUnaire>");

    }

    return operateur;

}

Noeud* LecteurPhraseAbstrait::relation() {

    Noeud* exp = expression();

    while (ls->getSymCour() == "==" || ls->getSymCour() == "!=" ||

            ls->getSymCour() == ">=" || ls->getSymCour() == "<=" ||

            ls->getSymCour() == ">" || ls->getSymCour() == "<") {

        Symbole operateur = opRel();

        Noeud* exp2 = expression();

        exp = new NoeudOperateurBinaire(operateur, exp, exp2);

    }

    return exp;

}



////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAbstrait::testerSymCour(string ch) {
    if (ls->getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls->getLigne()
                << " - Colonne " << ls->getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls->getSymCour() << endl
                << endl;
        exit(0); // plus tard, on levera une exception
    }
}



////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAbstrait::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls->suivant();
}



////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAbstrait::erreur(string mess) {

    cout << endl << "-------- Erreur ligne " << ls->getLigne() << " - Colonne "

            << ls->getColonne() << endl << "   Attendu : " << mess << endl

            << "   Trouve  : " << ls->getSymCour() << endl << endl;

    exit(0); // plus tard, on levera une exception

}

Noeud* LecteurPhraseAbstrait::instSi() {

    NoeudInstSi *noeudSi = new NoeudInstSi;

    sauterSymCour("si");

    sauterSymCour("(");

    Noeud*cond = expBool();

    sauterSymCour(")");

    Noeud *seq = seqInst();

    noeudSi->ajoute(cond, seq);

    while (ls->getSymCour() == "sinonsi") {

        ls->suivant();

        sauterSymCour("(");

        cond = expBool();

        sauterSymCour(")");

        seq = seqInst();

        noeudSi->ajoute(cond, seq);

    }

    if (ls->getSymCour() == "sinon") {

        ls->suivant();

        noeudSi->ajoute(NULL, seqInst());

    }

    sauterSymCour("finsi");

    return noeudSi;

}

Noeud* LecteurPhraseAbstrait::instLire() {

    NoeudInstLire *noeudLire = new NoeudInstLire();

    sauterSymCour("lire");

    sauterSymCour("(");

    testerSymCour("<VARIABLE>");

    Noeud* var = ts.chercheAjoute(ls->getSymCour());

    ls->suivant();

    sauterSymCour(")");

    noeudLire->ajoute(var);

    return noeudLire;

}

Noeud* LecteurPhraseAbstrait::instEcrire() {

    NoeudInstEcrire *noeudEcrire = new NoeudInstEcrire();

    Noeud* var = NULL;

    sauterSymCour("ecrire");

    sauterSymCour("(");

    if (ls->getSymCour() == "<CHAINE>") {

        var = ts.chercheAjoute(ls->getSymCour());

        ls->suivant();

    } else
 {

        var = expression();

    }

    sauterSymCour(")");

    noeudEcrire->ajoute(var);

    return noeudEcrire;

}

Noeud* LecteurPhraseAbstrait::instTq() {
    NoeudInstTq *noeudTq = new NoeudInstTq;

    sauterSymCour("tantque");

    sauterSymCour("(");

    Noeud* exp = expBool();

    sauterSymCour(")");

    Noeud *seq = seqInst();

    noeudTq->ajoute(exp, seq);

    sauterSymCour("fintantque");

    return noeudTq;

}

Noeud* LecteurPhraseAbstrait::instPour() {

    NoeudInstPour *noeudPr = new NoeudInstPour;

    sauterSymCour("pour");

    sauterSymCour("(");

    Noeud* affect1 = affectation();

    sauterSymCour(";");

    Noeud* exp = expBool();

    sauterSymCour(";");

    Noeud* affect2 = affectation();

    sauterSymCour(")");

    Noeud *seq = seqInst();

    noeudPr->ajoute(affect1, exp, affect2, seq);

    sauterSymCour("finpour");

    return noeudPr;



}

Noeud* LecteurPhraseAbstrait::instRepeter() {

    NoeudInstRepeter *noeudRp = new NoeudInstRepeter;

    sauterSymCour("repeter");

    Noeud* seq = seqInst();

    sauterSymCour("jusqua");

    sauterSymCour("(");

    Noeud* exp = expBool();

    noeudRp->ajoute(seq, exp);

    sauterSymCour(")");

    return noeudRp;

}